#include "gameState.h"
#include "evaluationFunction.h"
#include <iostream>
#include <vector>
#include <math.h>

#include <utility>
#include <algorithm>

#include <cstdlib>

GameState randomState(GameState &st, int moves);
    
Evaluation minMaxSimple(GameState &state, int depth);
Move getBest(GameState &state, int depth);

void hashTest(int table_size, int count);
std::vector<GameState> allStates(std::vector<GameState>& actual);

int main()
{
    GameState curr = GameState();
    srand ( time(NULL) );

		
    GameState start = GameState();
    GameState n = randomState(start, 38);

    start.print();

    std::vector<Move> moves = n.generateAllSimpleMoves(n.round, false);
    //for(int i = 0; i < moves.size(); i++)
     //   std::cout << moves[i];
        
    /*
    for(int j = 0; j < 8; j++)
    {
        for(int k = 0; k < 8; k++)
        {
            std::cout << Util::pieceColour(n.board[j][k]) << " ";
        }
        std::cout << "\n";   
    } 
    std::cout << "\n";  
    */
    
    for(int i = 0; i < 2; i++)
    {
        for(int j = 0; j < 8; j++)
        {
            for(int k = 0; k < 8; k++)
            {
                std::cout << n.attackInfo[i][j][k] << " ";
            }
            std::cout << "\n";   
        }
        std::cout << "\n\n";
    }
    
    int z;
    std::cin >> z;
    
    return 0;
}



std::vector<GameState> allStates(std::vector<GameState>& actual)
{
    srand ( time(NULL) );
    std::vector<GameState> states;
    
    for(int i = 0; i < actual.size(); i++)
    {
        std::vector<Move> moves = states[i].generateAllMoves();
        for(int j = 0; j < moves.size();  j++)
        {
             states.push_back(actual[i].applyMove(moves[j]));  
        }
    }
    
    return states;
}


double odchylenie(size_t* table, double count, int size)
{
    int sum = 0;   
    double dobry = count / size;
    
    for(int i = 0; i < size; i++)
        sum += abs(int(table[i] - dobry));
    
    return sum / (double)size;
}

void hashTest(int table_size, int count)
{
    size_t* table = new size_t[table_size];
    srand ( time(NULL) );
    
    for(int i = 0; i < table_size; i++)
        table[i] = 0;
        
    for(int i = 0; i < count; i++)
    {
        GameState s = GameState();
        GameState nowy = randomState(s,rand()%70);    
        table[s.hash() % table_size]++;
    }
    
    int max = 0;
    int c0 = 0;
    
    for(int i = 0; i < table_size; i++)
    {
        if(max < table[i])
            max = table[i];
        if(table[i] == 0)
            c0++;
    }
    std::cout << odchylenie(table, (double)count, table_size ) << "\n";
    delete table;
}


Move getBest(GameState &state, int depth)
{ 
    std::vector<Move> possibleMoves;
    GameState tempState;
    Colour player = state.round;
    
    if(player == WHITE)
    {
        possibleMoves = state.generateAllMoves();
        tempState = state.applyMove(possibleMoves[0]);
        Evaluation currentMin = minMaxSimple(tempState, depth-1);
        int currentBestMove = 0;
        
        // TODO is it better or worse to use an iterator ?
        for(int i = 1; i < possibleMoves.size(); i++)
        {
            tempState = state.applyMove(possibleMoves[i]);
            Evaluation current = minMaxSimple(tempState, depth-1);
            if(current < currentMin)
            {
                currentMin = current;
                currentBestMove = i;   
            }
        }
        return possibleMoves[currentBestMove];
    }
    else
    {
        possibleMoves = state.generateAllMoves();
        tempState = state.applyMove(possibleMoves[0]);
        Evaluation currentMax = minMaxSimple(tempState, depth-1);
        int currentBestMove = 0;
        
        // TODO is it better or worse to use an iterator ?
        for(int i = 1; i < possibleMoves.size(); i++)
        {
            tempState = state.applyMove(possibleMoves[i]);
            Evaluation current = minMaxSimple(tempState, depth-1);
            if(currentMax < current)
            {
                currentMax = current;
                currentBestMove = i;
            }
        }
        return possibleMoves[currentBestMove];
    }
}


//  WHITE is always minimalyzing, BLACK maximalyzing
Evaluation minMaxSimple(GameState &state, int depth)
{
    if(depth == 0)
        return Evaluation(state);
    
    std::vector<Move> possibleMoves;
    GameState tempState;
    Colour player = state.round;
    
    if(player == WHITE)
    {
        possibleMoves = state.generateAllMoves();
        tempState = state.applyMove(possibleMoves[0]);
        Evaluation currentMin = minMaxSimple(tempState, depth-1);
        
        // TODO is it better or worse to use an iterator ?
        for(int i = 1; i < possibleMoves.size(); i++)
        {
            tempState = state.applyMove(possibleMoves[i]);
            Evaluation current = minMaxSimple(tempState, depth-1);
            if(current < currentMin)
                currentMin = current;
        }
        return currentMin;
    }
    else
    {
        possibleMoves = state.generateAllMoves();
        tempState = state.applyMove(possibleMoves[0]);
        Evaluation currentMax = minMaxSimple(tempState, depth-1);
        
        // TODO is it better or worse to use an iterator ?
        for(int i = 1; i < possibleMoves.size(); i++)
        {
            tempState = state.applyMove(possibleMoves[i]);
            Evaluation current = minMaxSimple(tempState, depth-1);
            if(currentMax < current)
                currentMax = current;
        }
        return currentMax;  
        
    }
   
    return Evaluation(state);
}


GameState randomState(GameState &st, int moves)
{   
    GameState& tmp = st;
    
    for(int i = 0; i < moves; i++)
    {
        std::vector<Move> moves = tmp.generateAllSimpleMoves(tmp.round, false);
        
        std::vector<Move> specialMoves = tmp.generateAllSpecialMoves();


        Move toApply = moves[rand() % moves.size()];
        tmp = tmp.applyMove(toApply);    
    }
    return tmp;
}




